昨天, 我們知道了 JS 層藉由 V8 引用 C++ 層, C++ 層又利用 AIO (非同步IO) 註冊事件, 接著我們就來看看負責處理事件的 libuv 在做甚麼吧。
https://github.com/nodejs/node/blob/master/src/node_main.cc
來到 C++ 層的運行起點
int main(int argc, char* argv[]) {
#if defined(__POSIX__) && defined(NODE_SHARED_MODE)
// In node::PlatformInit(), we squash all signal handlers for non-shared lib
// build. In order to run test cases against shared lib build, we also need
// to do the same thing for shared lib build here, but only for SIGPIPE for
// now. If node::PlatformInit() is moved to here, then this section could be
// removed.
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
}
#endif
#if defined(__linux__)
node::per_process::linux_at_secure = getauxval(AT_SECURE);
#endif
// Disable stdio buffering, it interacts poorly with printf()
// calls elsewhere in the program (e.g., any logging from V8.)
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
return node::Start(argc, argv);
}
重點其實就是最後的 node::Start(argc, argv);
int Start(int argc, char** argv) {
InitializationResult result = InitializeOncePerProcess(argc, argv);
if (result.early_return) {
return result.exit_code;
}
{
Isolate::CreateParams params;
const std::vector<size_t>* indices = nullptr;
const EnvSerializeInfo* env_info = nullptr;
bool use_node_snapshot =
per_process::cli_options->per_isolate->node_snapshot;
if (use_node_snapshot) {
v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob();
if (blob != nullptr) {
params.snapshot_blob = blob;
indices = NodeMainInstance::GetIsolateDataIndices();
env_info = NodeMainInstance::GetEnvSerializeInfo();
}
}
uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);
NodeMainInstance main_instance(¶ms,
uv_default_loop(),
per_process::v8_platform.Platform(),
result.args,
result.exec_args,
indices);
result.exit_code = main_instance.Run(env_info);
}
TearDownOncePerProcess();
return result.exit_code;
}
可以看到實體化了一個 NodeMainInstance , 接著調用了該物件的 Run
void NodeMainInstance::Run(int* exit_code, Environment* env) {
if (*exit_code == 0) {
LoadEnvironment(env, StartExecutionCallback{});
*exit_code = SpinEventLoop(env).FromMaybe(1);
}
ResetStdio();
// TODO(addaleax): Neither NODE_SHARED_MODE nor HAVE_INSPECTOR really
// make sense here.
#if HAVE_INSPECTOR && defined(__POSIX__) && !defined(NODE_SHARED_MODE)
struct sigaction act;
memset(&act, 0, sizeof(act));
for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF)
continue;
act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
CHECK_EQ(0, sigaction(nr, &act, nullptr));
}
#endif
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
#endif
}
找到 SpinEventLoop 這就是 Event loop (libuv) 的創建入口
補充 : LoadEnvironment(env, StartExecutionCallback{}); 這聚會往上創建 JS 層, 但基於主體, 不深入細講。
所以可以視為, 這個函數裡面的兩句, 分別往上建立 JS 層, 和往下建立 libuv 層
// Runs the main loop for a given Environment. This roughly performs the
// following steps:
// 1. Call uv_run() on the event loop until it is drained.
// 2. Call platform->DrainTasks() on the associated platform/isolate.
// 3. If the event loop is alive again, go to Step 1.
// 4. Call EmitProcessBeforeExit().
// 5. If the event loop is alive again, go to Step 1.
// 6. Call EmitProcessExit() and forward the return value.
// If at any point node::Stop() is called, the function will attempt to return
// as soon as possible, returning an empty `Maybe`.
// This function only works if `env` has an associated `MultiIsolatePlatform`.
NODE_EXTERN v8::Maybe<int> SpinEventLoop(Environment* env);
查看註解可以得知其會運行 uv_run() method , 而這就是 libuv 的核心循環。
而這句函式, 就是從 C++ 層走入 libuv 的入口。
今天從 C++ 層調用了外部方法準備運行 uv_run() , 這據說是 libuv 的核心循環, 明天一起來看看吧 !
明天見 !